//********************************************************************************************************************//
//ORGANIZATION:
//AUTHOR: bpeng(bogers.peng@gmail.com)
//SUMMARY:
//********************************************************************************************************************//
#ifndef NATIVE_SYSTEM_BASE_MAPITERATOR_H
#define NATIVE_SYSTEM_BASE_MAPITERATOR_H

#ifndef NATIVE_SYSTEM_BASE_MAP_H
#include "System/Base/Map.h"
#endif
#ifndef NATIVE_SYSTEM_BASE_ITERATE_H
#include "System/Base/Iterate.h"
#endif

namespace Native { namespace System
{
    //****************************************************************************************************************//
    //CMapIterator
    //
    //****************************************************************************************************************//
    template<
        typename _TKey,
        typename _TValue,
        bool _FORWARD = true
    >
    class NATIVE_LIBRARY_EXPORT CMapIterator :
        public CObject,
        public IIterate<CDuad<_TKey, _TValue>>
    {
        NATIVE_DECLARE_OBJECT;

    public:
        NATIVE_REDEFINE(public, _TKey, TKey, T_KEY);
        NATIVE_REDEFINE(public, _TValue, TValue, T_VALUE);
        NATIVE_REDEFINE(
            public,
            CMapIterator<TKey COMMA TValue COMMA _FORWARD>,
            Class,
            CLASS);

    protected:
        const CMap<TKey, TValue>* _map;
        CMapCursor<TKey, TValue> _cursor;
        CDuad<TKey, TValue> _current;

        void _March()
        {
            _FORWARD? _cursor.Forward() : _cursor.Back();
            _current.Set(_cursor.Key(), _map->Value(_cursor));
        };

    protected:
        CMapIterator() :
            _map(nullptr)
        {};
    public:
        CMapIterator(CLASS& that) :
            CObject(that),
            _map(that._map),
            _cursor(that._cursor),
            _current(that._current)
        {};

        CMapIterator(CLASS&& that) :
            CObject(that),
            _map(that._map),
            _cursor(that._cursor),
            _current(that._current)
        {};

        CMapIterator(const CMap<TKey, TValue>* map) throw()
        {
            CNullPointerException::Check(NATIVE_SCENE(L"CMapIterator"), (POINTER)map, L"map");

            _map = map;
        };

        virtual ~CMapIterator()
        {};

        virtual CDuad<TKey, TValue>* First()
        {
            _FORWARD?
                _cursor = _map->LocateFirst() :
                _cursor = _map->LocateLast();

            if (_cursor.Exist()) {
                _current.Set(_cursor.Key(), _map->Value(_cursor));

                return &_current;
            } else {
                return nullptr;
            }
        };

        virtual CDuad<TKey, TValue>* Next()
        {
            if (_cursor.Exist()) {
                if (Done()) {
                    return nullptr;
                } else {
                    _March();

                    return &_current;
                }
            } else {
                return nullptr;
            }
        };

        virtual bool Done() const
        {
            if (_cursor.Exist()) {
                return _FORWARD?
                    _map->AtEnding(_cursor.Key()) : _map->AtBeginning(_cursor.Key());
            } else {
                return true;
            }
        };

        virtual CDuad<TKey, TValue>* Current()
        {
            return _cursor.Exist()? &_current : nullptr;
        };

        CLASS& operator=(CLASS& rvalue)
        {
            CObject::operator=(rvalue);

            _map = rvalue._map;
            _cursor = rvalue._cursor;
            _current = rvalue._current;

            return *this;
        };
    };
}}

#endif